#include "Fraction.h"
//Implementation of methods in Fraction class


void fraccpy(Fraction * dest, const Fraction * src){
	if (src == dest){
		return;
	}
	dest->p = src->p;
	dest->q = src->q;
	dest->sign = src->sign;
}

void inttofrac(Fraction * dest, const int src){
	dest->q = 1;
	if(src > 0){
		dest->sign = POSITIVE;
		dest->p = src;
	}else{
		dest->sign = NEGATIVE;
		dest->p = -src;
	}
}

void linttofrac(Fraction * dest, const long long int src){
	dest->q = 1;
	if(src > 0){
		dest->sign = POSITIVE;
		dest->p = src;
	}else{
		dest->sign = NEGATIVE;
		dest->p = -src;
	}
}

void makefrac(Fraction * dest, Integer numerator, Integer denominator, Sign sign){
	dest->p = numerator;
	dest->q = denominator;
	dest->sign = sign;
}

void fracinv(Fraction * dest, const Fraction * src){
	dest->p = src->q;
	dest->q = src->p;
	dest->sign = src->sign;
}



void fracreduce(Fraction * frac){
	if(frac->p == 0){
		frac->sign = NEGATIVE;
		frac->q = 1;
	}else{
		Integer d = gcd(frac->p, frac->q);
		frac->p = frac->p/d;
		frac->q = frac->q/d;
	}
}
	
void fracopp(Fraction * dest, const Fraction * src){
	if (src->p!=0){
		dest->p = src->p;
		dest->q = src->q;
		dest->sign = other(src->sign);
	}else{
		dest->p = 0;
		dest->q = 1;
		dest->sign = POSITIVE;
	}
	fracreduce(dest);
}


void fracplus(Fraction * dest, const Fraction * first, const Fraction * second){
	/*Find common denominator, (convert both fractions to that denominator - just store that as numbers),
	add them (watch out the signs) and then reduce the result*/
	Integer common_denominator = lcm(first->q, second->q); 
	Integer first_numerator = first->p*common_denominator/first->q;	//common_denominator/q is factor to multiply the numerator;
	Integer second_numerator = second->p*common_denominator/second->q;
	dest->q = common_denominator;
	if (first->sign == second->sign){
		dest->sign = first->sign;
		dest->p = first_numerator + second_numerator;
	}else{
		if(first_numerator > second_numerator){
			dest->sign = first->sign;
			dest->p = first_numerator - second_numerator;
		}else{
			dest->sign = second->sign;
			dest->p = second_numerator - first_numerator;
		}
	}
	fracreduce(dest);
}

void fracminus(Fraction * dest, const Fraction * first, const Fraction * second){
	Fraction temp;
	fracopp(&temp, second);
	fracplus(dest, first, &temp);
	/* dest is reduced */
}

void fracmul(Fraction * dest, const Fraction * first, const Fraction * second){
	/*Multiply numerators, multiply denominators, determine sign and return new fraction (constructor will reduce it);
	TODO: It can overflow and it does not have to, if we try to reduce what possible before multiplying.
	But how to do that? */
	dest->p = first->p * second->p;
	dest->q= first->q * second->q;
	dest->sign = (first->sign == second->sign) ? POSITIVE : NEGATIVE;
	fracreduce(dest);
}

void fracdiv(Fraction * dest, const Fraction * first, const Fraction * second){
	/*Multiply with inverse. */
	Fraction temp;
	fracinv(&temp, second);
	fracmul(dest, first, & temp);
	/* dest is reduced */
}

int fraccmp(const Fraction * first, const Fraction * second){
	Integer d;
	Integer first_numerator;
	Integer second_numerator;
	if (first->sign != second->sign){ /* if they have different signs */
		if (first->sign == NEGATIVE){
			return -1;
		}else{
			return 1;
		}
	}else{
		/*otherwise - same denominator... */
		d = lcm(first->q, second->q);
		first_numerator = first->p*d/first->q;
		second_numerator= second->p*d/second->q;
		if(first->sign == POSITIVE){
			if(first_numerator < second_numerator){
				return -1;
			}else if(first_numerator > second_numerator){
				return 1;
			}else{
				return 0;
			}
		}else{ /* negative */
			if(first_numerator < second_numerator){
				return 1;
			}else if(first_numerator > second_numerator){
				return -1;
			}else{
				return 0;
			}
		}
	}

}

/*
  This was from C++ version. Here I need to convert fraction to string. But how to do it properly?

std::ostream & operator<<(std::ostream & s, const Fraction & fraction){
	Integer num = fraction.get_numerator();
	Integer den = fraction.get_denominator();
	s << '(';
	if(den != 1){
		if(fraction.is_negative()){
			s << '-' << num << '/' << den;
		}else{
			s << num << '/' << den;
		}
	}else{
		if(fraction.is_negative()){
			s << '-' << num;
		}else{
			s << num;
		}
	}
	s << ')';
	return s;
}

*/
